在使用 Java Thread 開啟多執行的程式時,有時侯需要去等待其它的執行緒都執行完之後再啟動另外的執行緒,這時侯就可以使用 wait (等待) 和 notify (通知),二個互相搭配使用。
下面的例子來寫一個 sample code 在不使用 wait 和 notify 的情況下,從主程式開另外一個 thread 用來計算 1 加到 100,來看執行結果為何。Sample code 如下:
public class SumThread implements Runnable {
int sum = 0;
@Override
public void run() {
for (int i = 0 ; i <= 100 ; i++) {
sum = sum + i;
}
}
}
上面的程式碼是在執行 thread 時,使用迴圈將 1 加到 100,然後會把累加的結放在 sum 變數裡。
public class Test {
public static void main(String args[]) {
SumThread sum = new SumThread();
Thread thread = new Thread(sum);
thread.start();
int result = sum.sum;
System.out.println("Count result is:" + result);
}
}
在這裡的主程式會使用 SumThread 去啟動多執行結的程式,然後會把執行結果輸出,如下:
Count result is:0
我們會發現執行的結果是 0 ,這個計算結果是錯誤的。是因為在執行 Thread 時已經將結果先印出來之後,才完成 run 方法的計算 1 加到 100。因此造成執行的結果有問題。
要解這個問題就需要使用到 wait 和 notify,就是執行緒在還沒執行完之間 main 方法會先等待 (wait),等待執行緒執行完之後會通知 (notify) 執行完成了,這時侯輸出的執行結果才會是正確的。
修改完成的程式碼如下:
public class SumThread implements Runnable {
int sum = 0;
@Override
public void run() {
synchronized(this) {
for (int i = 0 ; i <= 100 ; i++) {
sum = sum + i;
}
notify();
}
}
}
以上 Thread 的程式如果執行完成就會發出通知 (notify) 執行完成了
public class Test {
public static void main(String args[]) throws Exception{
SumThread sum = new SumThread();
Thread thread = new Thread(sum);
thread.start();
synchronized(thread) {
thread.wait();
}
int result = sum.sum;
System.out.println("Count result is:" + result);
}
}
在主程式的部份會等待 (wait) Thread 執行完成之後,才會把結果印出來,執行結果如下:
Count result is:5050
這時輸出的結果才是正確的。因此如果在啟動執行緒時有考慮到執行順序的問題時,就可以使用 wait、notfiy 的方法。
幫你補充一個Java認證或面試常見考題:
Which are methods of the Object class? (Choose all that apply.)
✓ A. notify();
✓ B. notifyAll();
✗ C. isInterrupted();
✗ D. synchronized();
✗ E. interrupt();
✓ F. wait(1000L);
✗ G. sleep(1000L);
✗ H. yield()
謝謝啦!object class 的方法有 notify、notifyAll、wait。
JAVA API 網址如下:
https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html
請問wait與notify不是應該用在同一個物件上嗎,在SumThread裡的this應該指的是SumThread,跟主程式中的thread應該不是同一個物件。為什麼可以運作?
public class **SumThread** implements **Runnable**
明明就是 Runnable
還寫成 Thread
,看得我眼睛很花。害我看錯。
還以為可以 new Thread(thread)
爛死了。
然後程式還寫錯,根本不 work.
應該在 Runnable
裡面要寫 synchronized(thread)
而不是 synchronized(this)